/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ifpb.pod.servidor.funcinalidades;

import ifpb.pod.model.ContaUsuario;
import ifpb.pod.model.Contato;
import ifpb.pod.model.Noticia;
import ifpb.pod.model.Usuario;
import ifpb.pod.registro.Registro;
import ifpb.pod.remote.ClienteRemote;
import ifpb.pod.remote.ServidorRemote;
import java.net.MalformedURLException;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Diogenes
 */
public class ServidorRemoteImpl extends UnicastRemoteObject implements ServidorRemote {

    private Delegador delegador;
    private Map<String, ContaUsuario> contasOnline;

    public ServidorRemoteImpl() throws RemoteException {
        super();
        initialise();
    }

    private void initialise() {
        this.delegador = new Delegador();
//        this.contasOnline = new ArrayList<ContaUsuario>();
        this.contasOnline = new HashMap<String, ContaUsuario>();
    }

    public Boolean cadastrarUsuario(Usuario usuario) throws RemoteException {
        return this.delegador.cadastrarUsuario(usuario);
    }

    public Boolean atualizarUsuario(Usuario usuario) throws RemoteException {
        return this.delegador.atualizarUsuario(usuario);
    }

    public Boolean removerUsuario(Usuario usuario) throws RemoteException {
        return this.delegador.removerUsuario(usuario);
    }

    public Boolean autenticarUsuario(ContaUsuario conta) throws RemoteException {
        ContaUsuario contaUDoBanco = this.delegador.buscarContaUsuario(conta);
        if (contaUDoBanco != null) {
            Boolean retorno = verificaSenha(conta, contaUDoBanco);
            if (retorno) {
                addOnline(conta);
            }
            return retorno;
        }
        return Boolean.FALSE;
    }

    public void desautenticar(ContaUsuario conta) throws RemoteException {
        contasOnline.remove(conta.getLogin());
        notificaContatosOnline(conta);
    }

    public List<Contato> getContatosOnline(Usuario usuario) throws RemoteException {
        List<Contato> retorno = new ArrayList<Contato>();
        for (Contato contato : usuario.getContatos()) {
            ContaUsuario amigo = this.contasOnline.get(contato.getLogin());
            if (amigo != null) {
                Contato contatoAmigo = new Contato(amigo.getLogin());
                retorno.add(contatoAmigo);
            }
        }
        return retorno;
    }

    public List<Noticia> getNoticiasUsuario(Usuario u) throws RemoteException {
        return delegador.buscarNoticiasUsuario(u);
    }



    public Usuario addAmigoContato(Usuario usuario, String contato) throws RemoteException {
        Contato contatoAmigo = new Contato();
        contatoAmigo.setLogin(contato);
        Usuario novoUsuarioResposta = usuario;
        if (novoUsuarioResposta.addContato(contatoAmigo)) {
            if (atualizarUsuario(usuario)) {
                novoUsuarioResposta = buscarUsuario(usuario.getContaUsuario());
                Contato contatoUsuarioResposta = new Contato(novoUsuarioResposta.getContaUsuario().getLogin());
                ContaUsuario contatoAdd = new ContaUsuario();
                contatoAdd.setLogin(contato);
                Usuario usuarioContato = buscarUsuario(contatoAdd);
                try {
                    usuarioContato.addContato(contatoUsuarioResposta);
                    this.delegador.atualizarUsuario(usuarioContato);
                    ContaUsuario uc = new ContaUsuario();
                    uc.setLogin(contatoAmigo.getLogin());
                    System.out.println(uc.getLogin() + "-----------------");
                    notificaAmigo(uc);
                } catch (NullPointerException ex) {
                    System.out.println("olhaaiFacadeServidorImpl ta vindo null");
                    ex.printStackTrace();
                }
            }
        }
        return novoUsuarioResposta;

    }

    public Usuario buscarUsuario(ContaUsuario conta) throws RemoteException {
        return this.delegador.buscarUsuario(conta);
    }

    public ClienteRemote solicitarConversaCliente(Contato remetente, Contato destinatario) throws RemoteException {
        System.out.println("To solicitando");
        ClienteRemote cliente = null;
        try {
            try {
                cliente = (ClienteRemote) Registro.lookup(destinatario.getLogin());
            } catch (MalformedURLException ex) {
                Logger.getLogger(ServidorRemoteImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (NotBoundException ex) {
            System.out.println("Ta off");
        } catch (AccessException ex) {
            System.out.println("Não pode acessar");
        }
        return cliente;
    }

    public void conversar(Contato remetente, Contato destinatario) throws RemoteException {
        solicitarConversaCliente(remetente, destinatario).solicitarConversa(remetente);

    }

    public ClienteRemote solicitaConversaGrupo(Contato remetente, Contato convidado, List<Contato> contatosDaConversa) throws RemoteException {
        ClienteRemote cliente = null;
        try {
            try {
                cliente = (ClienteRemote) Registro.lookup(convidado.getLogin());
            } catch (MalformedURLException ex) {
                Logger.getLogger(ServidorRemoteImpl.class.getName()).log(Level.SEVERE, null, ex);
            }


            System.out.println("aviar os outros");
        } catch (NotBoundException ex) {
            ex.printStackTrace();
        }
        return cliente;

    }

    public void conversarGrupo(Contato remetente, Contato convidado, List<Contato> contatosDaConversa, Boolean mediador) throws RemoteException {
    }

    public void enviarNoticia(Noticia noticia, List<Contato> destinatarios) throws RemoteException {
        for (Contato contato : destinatarios) {
            ContaUsuario uc = new ContaUsuario();
            uc.setLogin(contato.getLogin());
            Usuario u = delegador.buscarUsuario(uc);
            if (u != null) {
//                delegador.salvarNoticia(noticia);
               Contato remetente = delegador.buscarContato(noticia.getRemetente());
               
               if(remetente!=null){
                   noticia.setRemetente(remetente);
                   u.addNoticia(noticia);
//                u.addContato(contato);
                System.out.println(u.getNome()+"Vai totoototototot");
                if (delegador.atualizarUsuario(u)) {
                    notificarContatosChegouNoticia(contato);
                }
               }

            }
        }




    }

    private void notificarContatosChegouNoticia(Contato destinatario) {
            try {
                ClienteRemote cliente = null;
            try {
                cliente = (ClienteRemote) Registro.lookup(destinatario.getLogin());
            } catch (MalformedURLException ex) {
                Logger.getLogger(ServidorRemoteImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
                cliente.notificarNoticia();
            } catch (RemoteException ex) {
                ex.printStackTrace();
            } catch (NotBoundException ex) {
                ex.printStackTrace();
            }

    }

    private Boolean verificaSenha(ContaUsuario conta, ContaUsuario outra) {
        return conta.getSenha().equals(outra.getSenha());
    }

    private void addOnline(ContaUsuario uc) {
//        if (!this.contasOnline.contains(uc)) {
//            Boolean contem = false;
//            for (ContaUsuario conta : this.contasOnline) {
//                if (conta.getLogin().equals(uc.getLogin())) {
//                    contem = true;
//                    break;
//                }
//            }
//            if (!contem) {
//                this.contasOnline.add(uc);
//        System.out.println(uc.getLogin()+"Essa é a conta para add");
//        System.out.println(this.contasOnline.size());
        this.contasOnline.put(uc.getLogin(), uc);
//        System.out.println(this.contasOnline.size());
//        System.out.println(uc.getLogin()+"zebra");
//        for (String object : contasOnline.keySet()) {
//            System.out.println("Olha aiiiii"+object);
//            System.out.println(contasOnline.get(object).getLogin()+"o objeto");
//
//        }
        notificaContatosOnline(uc);
//            }

//        }
    }

    private void notificaContatosOnline(ContaUsuario uc) {
        Usuario usuario;
        try {
            usuario = buscarUsuario(uc);
            for (Contato amigo : usuario.getContatos()) {
                ContaUsuario contaUsuarioAmigo = contasOnline.get(amigo.getLogin());
                if (contaUsuarioAmigo != null) {
                    notificaAmigo(contaUsuarioAmigo);
                }
//                System.out.println(contaUsuarioAmigo.getLogin()+"Amigo");

            }
//            for (String chaves : contasOnline.keySet()) {
//                System.out.println("Chave: "+chaves);
//            }
            System.out.println("-----------------------");
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }

    private void notificaAmigo(ContaUsuario contaUsuarioNotificar) {
//        Registro registry;
        try {
//            registry = new Registro();
//                    LocateRegistry.getRegistry(10790);
            ClienteRemote cliente;
            try {
                cliente = (ClienteRemote) Registro.lookup(contaUsuarioNotificar.getLogin());
                cliente.notificaStatusUsuario();
            } catch (MalformedURLException ex) {
                Logger.getLogger(ServidorRemoteImpl.class.getName()).log(Level.SEVERE, null, ex);
            }
//            Contato contatoAmigo = new Contato(uc.getLogin());
//            cliente.amigoEntrou(contatoAmigo);
            
        } catch (NullPointerException ex) {
            System.out.println("Ainda não tem registro");
        } catch (NotBoundException ex) {
//               ex.printStackTrace();
            System.out.println("Não encontrado registro");
        } catch (AccessException ex) {
            ex.printStackTrace();
        } catch (RemoteException ex) {
            ex.printStackTrace();
        }
    }
}
